home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus Special 25
/
AMIGAplus Sonderheft 25 (2000)(Falke)(DE)(Track 1 of 4)[!].iso
/
Tools
/
Text-Viewer
/
MSWordView
/
mswordview_src
/
roman.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-05-08
|
10KB
|
368 lines
/* roman.c by Adam Rogoyski (apoc@laker.net) Temperanc on EFNet irc
* Copyright (C) 1998 Adam Rogoyski
* Converts Decimal numbers to Roman Numerals and Roman Numberals to
* Decimals on the command line or in Interactive mode.
* Uses an expanded Roman Numeral set to handle numbers up to 999999999
* compile: gcc -o roman roman.c -O2
* --- GNU General Public License Disclamer ---
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern FILE *erroroutput;
#define I 1
#define V 5
#define X 10
#define L 50
#define C 100
#define D 500
#define M 1000
#define P 5000
#define Q 10000
#define R 50000
#define S 100000
#define T 500000
#define U 1000000
#define B 5000000
#define W 10000000
#define N 50000000
#define Y 100000000
#define Z 500000000
#define LARGEST 999999999
#include "roman.h"
#if 0
int
main (int argc, char **argv)
{
char roman[81];
int i = 0;
long decimal = 0;
if (argc < 2)
{
char *buf = malloc (81);
if (!buf)
{
fprintf (erroroutput, "Not enough memory\n");
exit (EXIT_FAILURE);
}
printf ("Decimal <=> Roman Numberal converter by Adam Rogoyski\n");
printf ("Enter Decimals or Romans to convert, quit to stop\n");
printf ("Range: 1-999999999, I-ZYZWYUWSUQSMQCMXCIX\n\n==> ");
fflush (stdout);
memset (buf, 0, 81);
while (strncasecmp(fgets(buf, 81, stdin) ? buf : "", "quit", 4))
{
if (!buf[0])
exit (EXIT_SUCCESS);
i = 0;
while (isspace(buf[i]))
i++;
if (isdigit(buf[i]))
puts (decimalToRoman(atoi(buf), roman));
else
{
if (isupper(buf[i]))
{
chomp (buf);
decimal = romanToDecimal(buf);
if (decimal)
printf ("%ld\n", decimal);
}
}
printf ("==> ");
fflush (stdout);
memset (buf, 0, 80);
}
free (buf);
}
else
{
while (argc-- >= 2)
{
memset (roman, 0, 81);
if (isdigit(**(argv + 1)))
{
decimal = atoi (*(argv + 1));
puts (decimalToRoman(decimal, roman));
}
else
{
decimal = romanToDecimal(*(argv + 1));
if (decimal)
printf ("%ld\n", decimal);
}
argv++;
}
}
return EXIT_SUCCESS;
}
#endif
long
formString (char **r, long v, char a, char b)
{
*(*r)++ = a;
if (b)
*(*r)++ = b;
return v;
}
char * decimalToRoman (long decimal, char *roman)
{
char *r = roman;
memset (roman, 0, 81);
r = roman;
if (decimal > LARGEST || decimal < 1)
{
*r = '\0';
fprintf(erroroutput,"roman broke\n");
return roman;
}
if (decimal >= Z)
decimal -= formString (&r, Z, 'Z', '\0');
if (decimal >= Z - Y)
decimal -= formString (&r, Z - Y, 'Y', 'Z');
while (decimal >= Y)
decimal -= formString (&r, Y, 'Y', '\0');
if (decimal >= Y - W)
decimal -= formString (&r, Y - W, 'W', 'Y');
if (decimal >= N)
decimal -= formString (&r, N, 'N', '\0');
if (decimal >= N - W)
decimal -= formString (&r, N - W, 'W', 'N');
while (decimal >= W)
decimal -= formString (&r, W, 'W', '\0');
if (decimal >= W - U)
decimal -= formString (&r, W - U, 'U', 'W');
if (decimal >= B)
decimal -= formString (&r, B, 'B', '\0');
if (decimal >= B - U)
decimal -= formString (&r, B - U, 'U', 'B');
while (decimal >= U)
decimal -= formString (&r, U, 'U', '\0');
if (decimal >= U - S)
decimal -= formString (&r, U - S, 'S', 'U');
if (decimal >= T)
decimal -= formString (&r, T, 'T', '\0');
if (decimal >= T - S)
decimal -= formString (&r, T - S, 'S', 'T');
while (decimal >= S)
decimal -= formString (&r, S, 'S', '\0');
if (decimal >= S - Q)
decimal -= formString (&r, S - Q, 'Q', 'S');
if (decimal >= R)
decimal -= formString (&r, R, 'R', '\0');
if (decimal >= R - Q)
decimal -= formString (&r, R - Q, 'Q', 'R');
while (decimal >= Q)
decimal -= formString (&r, Q, 'Q', '\0');
if (decimal >= Q - M)
decimal -= formString (&r, Q - M, 'M', 'Q');
if (decimal >= P)
decimal -= formString (&r, P, 'P', '\0');
if (decimal >= P - M)
decimal -= formString (&r, P - M, 'M', 'P');
while (decimal >= M)
decimal -= formString (&r, M, 'M', '\0');
if (decimal >= M - C)
decimal -= formString (&r, M - C, 'C', 'M');
if (decimal >= D)
decimal -= formString (&r, D, 'D', '\0');
if (decimal >= D - C)
decimal -= formString (&r, D - C, 'C', 'D');
while (decimal >= C)
decimal -= formString (&r, C, 'C', '\0');
if (decimal >= C - X)
decimal -= formString (&r, C - X, 'X', 'C');
if (decimal >= L)
decimal -= formString (&r, L, 'L', '\0');
if (decimal >= L - X)
decimal -= formString (&r, L - X, 'X', 'L');
while (decimal >= X)
decimal -= formString (&r, X, 'X', '\0');
switch ((int) decimal)
{
case 9:
*r++ = 'I';
*r++ = 'X';
break;
case 8:
*r++ = 'V';
*r++ = 'I';
*r++ = 'I';
*r++ = 'I';
break;
case 7:
*r++ = 'V';
*r++ = 'I';
*r++ = 'I';
break;
case 6:
*r++ = 'V';
*r++ = 'I';
break;
case 4:
*r++ = 'I';
case 5:
*r++ = 'V';
break;
case 3:
*r++ = 'I';
case 2:
*r++ = 'I';
case 1:
*r++ = 'I';
break;
}
return roman;
}
long
romanToDecimal (char *roman)
{
long decimal = 0;
for (; *roman; roman++)
{
/* Check for four of a letter in a fow */
if ((*(roman + 1) && *(roman + 2) && *(roman + 3))
&& (*roman == *(roman + 1))
&& (*roman == *(roman + 2))
&& (*roman == *(roman + 3)))
return 0;
/* Check for two five type numbers */
if ( ((*roman == 'V') && (*(roman + 1) == 'V'))
|| ((*roman == 'L') && (*(roman + 1) == 'L'))
|| ((*roman == 'D') && (*(roman + 1) == 'D'))
|| ((*roman == 'P') && (*(roman + 1) == 'P'))
|| ((*roman == 'R') && (*(roman + 1) == 'R'))
|| ((*roman == 'T') && (*(roman + 1) == 'T'))
|| ((*roman == 'B') && (*(roman + 1) == 'B'))
|| ((*roman == 'N') && (*(roman + 1) == 'N'))
|| ((*roman == 'Z') && (*(roman + 1) == 'Z')))
return 0;
/* Check for two lower characters before a larger one */
if ((value(*roman) == value(*(roman + 1))) && (*(roman + 2))
&& (value(*(roman + 1)) < value(*(roman + 2))))
return 0;
/* Check for the same character on either side of a larger one */
if ((*(roman + 1) && *(roman + 2))
&& (value(*roman) == value(*(roman + 2)))
&& (value(*roman) < value(*(roman + 1))))
return 0;
/* Check for illegal nine type numbers */
if (!strncmp(roman, "LXL", 3) || !strncmp(roman, "DCD", 3)
|| !strncmp(roman, "PMP", 3) || !strncmp(roman, "RQR", 3)
|| !strncmp(roman, "TST", 3) || !strncmp(roman, "BUB", 3)
|| !strncmp(roman, "NWN", 3) || !strncmp(roman, "VIV", 3))
return 0;
if (value(*roman) < value(*(roman + 1)))
{
/* check that subtracted value is at least 10% larger,
i.e. 1990 is not MXM, but MCMXC */
if ((10 * value(*roman)) < value(*(roman + 1)))
return 0;
/* check for double subtraction, i.e. IVX */
if (value(*(roman + 1)) <= value(*(roman + 2